package org.fast.develop.logicflow.runtime.expression;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.googlecode.aviator.AviatorEvaluator;
import lombok.extern.slf4j.Slf4j;
import org.fast.develop.logicflow.runtime.PersistEnum2DB;
import org.fast.develop.logicflow.runtime.exception.LogicFlowException;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author 莫寅
 * @createTime 2022-11-24 19:13
 * @desc：
 */
@Slf4j
public class ExpressionExecutor {

    /**
     * 表达式缓存
     */
    private Map<String, com.googlecode.aviator.Expression> Expression = new HashMap();

    public com.googlecode.aviator.Expression compile(String str){
        return getExpression(str);
    }

    public Object execute(String str, Map m){
        HashMap vars = (HashMap) ((HashMap) m).clone();
        String expression = replaceParam(str, vars);
        return compile(expression).execute(m);
    }

    public Boolean executeBoolean(String str, Map m){
        HashMap vars = (HashMap) ((HashMap) m).clone();
        String expression = replaceParam(str, vars);

        Object result = compile(expression).execute(m);

        if(result instanceof Boolean){
            return (Boolean)result;
        }else{
            log.error("不是一个boolean类型结果" );
            return false;
        }
    }

    public Object executeDecimal(String str, Map m){
        HashMap vars = (HashMap) ((HashMap) m).clone();
        String expression = replaceParam(str, vars, FormatType.BigDecimal);
        return compile(expression).execute(m);
    }

    private com.googlecode.aviator.Expression getExpression(String str) {
        if(Expression.get(str) == null){
            Expression.put(str, AviatorEvaluator.compile(str));
        }
        return Expression.get(str);
    }


    /**
     * 判断是否全部都有
     * @param str
     * @param map
     * @return
     */
    private boolean all_true(String str, Map map){
        boolean flag = true;
//        Expression expression = AviatorEvaluator.compile(str);
        com.googlecode.aviator.Expression expression = compile(str);
        if(expression.getVariableFullNames().size() == 0){
            return false;
        }

        for (String s:expression.getVariableFullNames()
        ) {
            if(null == map.get(s)){
                flag = false;
                break;
            }
        }
        return flag;
    }


    /**
     * 替换公式
     * @param str
     * @param map
     * @return
     */
    private String replaceParam(String str, Map map){

        return replaceParam(str, map, null);
    }

    /**
     * 替换公式
     * @param str
     * @param map
     * @return
     */
    private String replaceParam(String str, Map map, FormatType formatType){
        String expressionContent = getContentInfo(str);
        if(StrUtil.isBlank(expressionContent)){
            throw new LogicFlowException("公式格式不正确，请输入${}格式的公式");
        }
        com.googlecode.aviator.Expression expression = compile(expressionContent);
        for (String s:expression.getVariableFullNames()
        ) {
            String regex = "\\b"+s+"\\b";
            Pattern p = Pattern.compile(regex);
            Matcher m = p.matcher(expressionContent);

            Object value = getValue(map, s);

            if(formatType != null && NumberUtil.isNumber(value.toString())){
                value = value + formatType.value;
            }else if(value instanceof String){
                String content = getContentInfo((String) value);
                if(StrUtil.isNotBlank(content)){
                    com.googlecode.aviator.Expression valueExpression = compile(content);
                    if(valueExpression.getVariableFullNames().size() > 0){
                        value = replaceParam((String) value, map, formatType);
                    }
                }
            }

            if(value != null){
                expressionContent = m.replaceAll(formatNull_String(value));
            }
        }
        return expressionContent;
    }


    public static String formatNull_String(Object value){
        if(null == value){
            return "";
        }else{
            return value.toString();
        }
    }

    public static boolean isNumeric(String str){
        for (int i = 0; i < str.length(); i++){
            System.out.println(str.charAt(i));
            if (!Character.isDigit(str.charAt(i))){
                return false;
            }
        }
        return true;
    }

    /**
     * 获取表达式中${}中的值
     * @param content
     * @return
     */
    public static String getContentInfo(String content) {
        Pattern regex = Pattern.compile("^\\$\\{([^}]*)\\}$");
        Matcher matcher = regex.matcher(content);
        StringBuilder sql = new StringBuilder();
        while(matcher.find()) {
            sql.append(matcher.group(1)+",");
        }
        if (sql.length() > 0) {
            sql.deleteCharAt(sql.length() - 1);
        }
        return sql.toString();
    }

    public static void main(String[] args) {
        getContentInfo("${123}");
        System.out.println(123);

        ExpressionExecutor expressionExecutor = new ExpressionExecutor();
        Object o = expressionExecutor.execute("${1+1!=2?1:2}", new HashMap() );
        System.out.println(123);
    }


    // 处理包含数字
    private final static Pattern PATTERN_INDEX = Pattern
            .compile("^\\\\[(\\d+)\\\\]$");
    /**
     * Extracts a value from a target object using DPath expression.
     *
     * @param target
     * @param dPath
     */
    public static Object getValue(Object target, String dPath) {
        String[] paths = dPath.split("\\.");
        // 此处实现了一个可以支持递归模式的数据处理
        Object result = target;
        for (String path : paths) {
            result = extractValue(result, path);
        }
        return result;
    }


    private static Object extractValue(Object target, String index) {
        if (target == null) {
            throw new IllegalArgumentException();
        }
        Matcher m = PATTERN_INDEX.matcher(index);
        if (m.matches()) {
            int i = Integer.parseInt(m.group(1));
            if (target instanceof Object[]) {
                return ((Object[]) target)[i];
            }
            if (target instanceof List<?>) {
                return ((List<?>) target).get(i);
            }
            throw new IllegalArgumentException("Expect an array or list!");
        }
        if (target instanceof Map<?, ?>) {
            return ((Map<?, ?>) target).get(index);
        }
        throw new IllegalArgumentException();
    }


    public static enum FormatType implements PersistEnum2DB
    {
        BigInteger("N", "BigInteger"),
        BigDecimal("M", "BigDecimal");

        private String value;
        private String display;

        FormatType(String value, String display) {
            this.value = value;
            this.display = display;
        }


        public static FormatType create(Object name){
            return PersistEnum2DB.create(FormatType.class, name);
        }

        @Override
        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }

        @Override
        public String getDisplay() {
            return display;
        }

        public void setDisplay(String display) {
            this.display = display;
        }

    }

}

